package com.chinasoftinc.facommon.control.conversation;

import ohos.app.Context;
import ohos.bluetooth.BluetoothHost;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import com.huawei.ailife.service.kit.callback.BleDeviceDataListener;
import com.huawei.ailife.service.kit.callback.DataCallback;

import com.chinasoftinc.facommon.DeviceControlConstants;
import com.chinasoftinc.facommon.FAConfigMgr;
import com.chinasoftinc.facommon.utils.LogUtil;

/**
 * 蓝牙会话
 *
 * @since 2022-04-20
 */
public class BleConversation extends Conversation {
    public static final String TAG = "BleConversation";
    private static String sessionId;
    private final BluetoothHost bluetoothHost;
    private EventHandler eventHandler;
    private static Runner timeoutTask;
    private BleDeviceDataListener bleDeviceDataListener;

    public BleConversation(Context context) {
        bluetoothHost = BluetoothHost.getDefaultHost(context);
        eventHandler = new EventHandler(EventRunner.getMainEventRunner());
    }

    @Override
    public void connect() {
        dataChangeCallback
            .ifPresent(hiLinkDataCallback -> presentBleConnectStateChange(hiLinkDataCallback, BleConnectState.CONNECTING))
            .noPresent(WarnLog.INSTANCE);
        createTimeoutTask();
        if (bluetoothHost.getBtState() != BluetoothHost.STATE_ON) {
            bluetoothHost.enableBt();
            dataChangeCallback
                    .ifPresent(hiLinkDataCallback -> presentBleConnectStateChange(hiLinkDataCallback, BleConnectState.UN_CONNECT))
                    .noPresent(WarnLog.INSTANCE);
            return;
        }

        LogUtil.info(TAG, "connect device");
        hiLinkDevice.connectBleDevice(new DataCallback<String>() {
            @Override
            public void onSuccess(String sessionId) {
                LogUtil.info(TAG, " 连接成功 sessionId: " + sessionId);
                cancelTimeoutTask();
                BleConversation.sessionId = sessionId;
                dataChangeCallback
                    .ifPresent(hiLinkDataCallback -> presentBleConnectStateChange(hiLinkDataCallback, BleConnectState.CONNECTED))
                    .noPresent(WarnLog.INSTANCE);
                subscribeDeviceEvent();
            }

            @Override
            public void onFailure(int errorCode, String msg) {
                LogUtil.info(TAG, " 连接失败, " + errorCode + msg);
                cancelTimeoutTask();
                dataChangeCallback
                    .ifPresent(hiLinkDataCallback ->
                        presentBleConnectStateChange(hiLinkDataCallback, BleConnectState.CONNECT_FAILED))
                    .noPresent(WarnLog.INSTANCE);
            }
        });

    }

    private void createTimeoutTask() {
        cancelTimeoutTask();
        timeoutTask = new Runner() {
            @Override
            public void run() {
                if (isCanceled) {
                    return;
                }
                LogUtil.info(TAG, " connect timeout..." + this);
                disconnect();
                dataChangeCallback
                    .ifPresent(hiLinkDataCallback -> presentBleConnectStateChange(hiLinkDataCallback, BleConnectState.CONNECT_FAILED))
                    .noPresent(WarnLog.INSTANCE);
            }
        };
        try {
            eventHandler.postTask(timeoutTask, FAConfigMgr.get().getBleConnectTimeOut());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void presentBleConnectStateChange(HiLinkDataCallback hiLinkDataCallback, BleConnectState state) {
        hiLinkDataCallback.onBleConnectStateChange(state.code(), state.msg());
    }

    private void cancelTimeoutTask() {
        eventHandler.removeAllEvent();
        if (timeoutTask != null) {
            timeoutTask.cancel();
        }
    }

    @Override
    public void disconnect() {
        if (hiLinkDevice != null) {
            hiLinkDevice.disconnectBleDevice(sessionId);
        }
        sessionId = null;
    }

    @Override
    public void init() {
    }

    @Override
    public void onDeviceIdChange() {
        super.onDeviceIdChange();
        if (bleDeviceDataListener != null) {
            try {
                hiLinkDevice.unsubscribeBleDeviceEvent(sessionId, bleDeviceDataListener);
                bleDeviceDataListener = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void subscribeDeviceEvent() {
        onDeviceIdChange();
        bleDeviceDataListener = new BleDeviceDataListener() {
            @Override
            public void onCharacteristicChanged(String bleTransData) {
                LogUtil.info(TAG, "onCharacteristicChanged" + bleTransData);
                dataChangeCallback
                    .ifPresent(hiLinkDataCallback -> hiLinkDataCallback.onSuccess(DeviceControlConstants.DATA_TYPE_BLE_CHARACTERISTIC_CHANGED, bleTransData))
                    .noPresent(WarnLog.INSTANCE);
            }

            @Override
            public void onConnectionStateChange(String mac, int status, int newStatus) {
                LogUtil.info(TAG, "onConnectionStateChange: " + newStatus);
                dataChangeCallback
                    .ifPresent(hiLinkDataCallback -> hiLinkDataCallback.onBleConnectStateChange(newStatus, ""))
                    .noPresent(WarnLog.INSTANCE);
            }
        };
        hiLinkDevice.subscribeBleDeviceEvent(sessionId, bleDeviceDataListener);
    }

    static abstract class Runner implements Runnable {
        boolean isCanceled;

        public void cancel() {
            this.isCanceled = true;
        }

    }
}
